package com.dlc.shop.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dlc.shop.bean.app.dto.MyOrderDto;
import com.dlc.shop.bean.enums.OrderStatus;
import com.dlc.shop.bean.enums.ProdWriteOffNumEnum;
import com.dlc.shop.bean.enums.RefundStatusEnum;
import com.dlc.shop.bean.enums.StationStatusEnum;
import com.dlc.shop.bean.event.ReceiptOrderEvent;
import com.dlc.shop.bean.model.Order;
import com.dlc.shop.bean.model.OrderVirtualInfo;
import com.dlc.shop.bean.model.OrderVirtualVerifyLog;
import com.dlc.shop.bean.model.Station;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.i18n.I18nMessage;
import com.dlc.shop.dao.OrderMapper;
import com.dlc.shop.dao.OrderVirtualInfoMapper;
import com.dlc.shop.dao.OrderVirtualVerifyLogMapper;
import com.dlc.shop.service.OrderVirtualInfoService;
import com.dlc.shop.service.StationService;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 订单虚拟商品信息
 *
 * @author lhd
 * @date 2021-09-15 15:45:35
 */
@Service
@AllArgsConstructor
public class OrderVirtualInfoServiceImpl extends ServiceImpl<OrderVirtualInfoMapper, OrderVirtualInfo> implements OrderVirtualInfoService {

    private final OrderVirtualInfoMapper orderVirtualInfoMapper;
    private final OrderVirtualVerifyLogMapper orderVirtualVerifyLogMapper;
    private final OrderMapper orderMapper;
    private final StationService stationService;
    private final ApplicationEventPublisher eventPublisher;

    @Override
    public String getNewCodeInfo(Long shopId) {
        return orderVirtualInfoMapper.getNewCodeInfo(shopId);
    }

    @Override
    public MyOrderDto getOrderByCode(Long shopId, String code) {
        return orderVirtualInfoMapper.getOrderByCode(shopId, code);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean orderWriteOffByOrderNumber(MyOrderDto myOrderDto, Order orderDb, Long stationId) {
        Date date = new Date();
        List<OrderVirtualInfo> orderVirtualInfoList = checkInfoAndGetVirtualInfo(myOrderDto, orderDb, stationId, date);
        //生成核销记录
        handleVirtualLog(myOrderDto, orderDb, stationId, date);
        // 是否全部核销完成
        boolean isAllWriteOff;
        // 核销码存在时表示直接是核销码核销，否则直接是整单核销
        if (Objects.nonNull(myOrderDto) && StrUtil.isNotBlank(myOrderDto.getWriteOffCode())) {
            isAllWriteOff = orderVirtualInfoList.size() < 2;
            for (OrderVirtualInfo orderVirtualInfo : orderVirtualInfoList) {
                if (StrUtil.equals(myOrderDto.getWriteOffCode(), orderVirtualInfo.getWriteOffCode())) {
                    orderVirtualInfo.setWriteOffTime(date);
                    orderVirtualInfo.setStationId(stationId);
                    // 多次核销次数还没到
                    if (Objects.equals(orderDb.getWriteOffNum(), -1) && 0 < orderVirtualInfo.getWriteOffMultipleCount() - 1) {
                        orderVirtualInfo.setWriteOffMultipleCount(orderVirtualInfo.getWriteOffMultipleCount() - 1);
                        isAllWriteOff = false;
                        continue;
                    }
                    orderVirtualInfo.setIsWriteOff(1);
                    break;
                }
            }
        } else {
            isAllWriteOff = true;
            for (OrderVirtualInfo orderVirtualInfo : orderVirtualInfoList) {
                orderVirtualInfo.setStationId(stationId);
                orderVirtualInfo.setWriteOffTime(date);
                if (Objects.equals(orderDb.getWriteOffNum(), -1) && Objects.equals(orderDb.getWriteOffMultipleCount(), -1) ) {
                    isAllWriteOff = false;
                    continue;
                }
                // 多次核销次数还没到
                if (Objects.equals(orderDb.getWriteOffNum(), -1) && 0 < orderVirtualInfo.getWriteOffMultipleCount() - 1) {
                    orderVirtualInfo.setWriteOffMultipleCount(orderVirtualInfo.getWriteOffMultipleCount() - 1);
                    isAllWriteOff = false;
                    continue;
                }
                orderVirtualInfo.setIsWriteOff(1);
            }
        }
        updateBatchById(orderVirtualInfoList);

        // 全部提货完成就直接确认收货
        if (isAllWriteOff) {
            orderDb.setWriteOffStatus(1);
            if (Objects.equals(orderDb.getStatus(), OrderStatus.CONSIGNMENT.value())) {
                orderDb.setStatus(OrderStatus.SUCCESS.value());
                orderDb.setFinallyTime(new Date());
                //添加积分
                eventPublisher.publishEvent(new ReceiptOrderEvent(orderDb));
            }
            orderMapper.updateById(orderDb);
        }
        return true;
    }

    private List<OrderVirtualInfo> checkInfoAndGetVirtualInfo(MyOrderDto myOrderDto, Order orderDb, Long stationId, Date date) {
        if (Objects.nonNull(stationId)) {
            Station station = stationService.getById(stationId);
            if (!Objects.equals(station.getStatus(), StationStatusEnum.OPEN.value())) {
                // 该自提点未在营业状态
                throw new YamiShopBindException("yami.shop.station.not.open");
            }
        }
        boolean isRefund = Objects.equals(orderDb.getRefundStatus(), RefundStatusEnum.APPLY.value())
                || Objects.equals(orderDb.getRefundStatus(), RefundStatusEnum.SUCCEED.value());
        if (Objects.nonNull(orderDb.getRefundStatus()) && isRefund) {
            // 订单退款中，无法核销
            throw new YamiShopBindException(I18nMessage.getMessage("yami.order") + orderDb.getOrderNumber() + I18nMessage.getMessage("yami.order.virtual.check"));
        }
        if (Objects.equals(orderDb.getWriteOffNum(), 0)) {
            // 订单无需核销
            throw new YamiShopBindException("yami.order.virtual.check2");
        }
        // 查询出未核销的卡券
        List<OrderVirtualInfo> orderVirtualInfoList = list(new LambdaQueryWrapper<OrderVirtualInfo>()
                .eq(OrderVirtualInfo::getOrderNumber, orderDb.getOrderNumber())
                .eq(OrderVirtualInfo::getShopId, orderDb.getShopId())
                .and(wrapper -> wrapper.eq(OrderVirtualInfo::getIsWriteOff, 0).or().eq(OrderVirtualInfo::getWriteOffMultipleCount, -1)));
        if (CollectionUtils.isEmpty(orderVirtualInfoList)) {
            // 卡券不存在或者已核销
            throw new YamiShopBindException("yami.order.coupon.exist");
        }
        if (0 < DateUtil.compare(orderDb.getWriteOffStart(), date)) {
            // 卡券未到使用时间或已过期
            throw new YamiShopBindException("yami.order.coupon.not.start");
        }
        if (Objects.nonNull(orderDb.getWriteOffEnd()) && DateUtil.compare(date, orderDb.getWriteOffEnd()) > 0) {
            // 卡券未到使用时间或已过期
            throw new YamiShopBindException("yami.order.coupon.not.start");
        }
        // 核销码是否存在
        if (Objects.nonNull(myOrderDto) && CharSequenceUtil.isNotBlank(myOrderDto.getWriteOffCode())) {
            boolean isExist = false;
            for (OrderVirtualInfo orderVirtualInfo : orderVirtualInfoList) {
                if (CharSequenceUtil.equals(myOrderDto.getWriteOffCode(), orderVirtualInfo.getWriteOffCode())) {
                    isExist = true;
                    break;
                }
            }
            if (!isExist) {
                // 卡券不存在或者已核销
                throw new YamiShopBindException("yami.order.code.no.error");
            }
        }
        return orderVirtualInfoList;
    }

    private boolean handleVirtualLog(MyOrderDto myOrderDto, Order orderDb, Long stationId, Date date) {
        //如果是批量核销,生成多条核销记录
        if (null == myOrderDto || null == myOrderDto.getWriteOffCode() || myOrderDto.getWriteOffCode().isEmpty()){
            List<OrderVirtualInfo> virtualInfos = list(new LambdaQueryWrapper<OrderVirtualInfo>()
                    .eq(OrderVirtualInfo::getOrderNumber, orderDb.getOrderNumber())
                    .eq(OrderVirtualInfo::getShopId, orderDb.getShopId())
                    .and(wrapper -> wrapper.eq(OrderVirtualInfo::getIsWriteOff, 0)
                            .or().eq(OrderVirtualInfo::getWriteOffMultipleCount, -1)));
            if (CollectionUtils.isNotEmpty(virtualInfos)) {
                for (OrderVirtualInfo virtualInfo : virtualInfos) {
                    OrderVirtualVerifyLog orderVirtualVerifyLog = new OrderVirtualVerifyLog();
                    orderVirtualVerifyLog.setOrderNumber(orderDb.getOrderNumber());
                    orderVirtualVerifyLog.setShopId(orderDb.getShopId());
                    orderVirtualVerifyLog.setStationId(stationId);
                    orderVirtualVerifyLog.setWriteOffCode(virtualInfo.getWriteOffCode());
                    orderVirtualVerifyLog.setCreateTime(date);
                    // 如果是多次核销且无限次则无需进行核销
                    boolean isNoNeedWriteOff = Objects.equals(orderDb.getWriteOffNum(), ProdWriteOffNumEnum.WRITE_OFF_MULTIPLE.value()) &&
                            (Objects.equals(orderDb.getWriteOffMultipleCount(), -1) || Objects.isNull(orderDb.getWriteOffMultipleCount()));
                    //生成核销记录
                    orderVirtualVerifyLogMapper.insert(orderVirtualVerifyLog);
                }
            }
        } else {
            OrderVirtualVerifyLog orderVirtualVerifyLog = new OrderVirtualVerifyLog();
            orderVirtualVerifyLog.setOrderNumber(orderDb.getOrderNumber());
            orderVirtualVerifyLog.setShopId(orderDb.getShopId());
            orderVirtualVerifyLog.setStationId(stationId);
            orderVirtualVerifyLog.setWriteOffCode(myOrderDto.getWriteOffCode());
            orderVirtualVerifyLog.setCreateTime(date);
            boolean writeOffCountCheck = Objects.equals(orderDb.getWriteOffMultipleCount(), -1) || Objects.isNull(orderDb.getWriteOffMultipleCount());
            // 如果是多次核销且无限次则无需进行核销
            if (Objects.equals(orderDb.getWriteOffNum(), -1) && writeOffCountCheck) {
                //生成核销记录
                orderVirtualVerifyLogMapper.insert(orderVirtualVerifyLog);
                return true;
            }
            orderVirtualVerifyLogMapper.insert(orderVirtualVerifyLog);
        }
        return false;
    }
}
